---
title: SAIF.Application architecture
summary: Architectural responsibilities, boundaries, and interaction patterns.
status: draft
owner: SAIF Documentation
last_reviewed: 2026-08-21
library: SAIF.Application
reference_type: embedded
---

# SAIF.Application architecture

`SAIF.Application` is the domain-neutral application layer foundation of the LegalMaintenance solution. It sits between the `SAIF.BOF.Framework` packages below and the domain-specific application layers (`SAIF.Application.Claim` → `SAIF.Application.Claim.Legal` → the `LegalMaintenance` WebForms front end) above, supplying the manager lifecycle contract, access-classification state machine, authorization result caching, data-portal provisioning, message accumulation, and a service-style response envelope, but no domain knowledge, SQL, or UI logic of its own.

## Responsibilities
- **Application manager contract** (`AppManagerBase`) — defines the lifecycle template every application process follows: construct-with-identity → `Initialize` → context validation → security evaluation → `Retrieve` / `Write` with transaction hooks. The base class supplies state and helpers; all behavior is deferred to `MustOverride` members.
- **Access classification state machine** (`AppSecurityRole` + `Mark*` methods + `Is*` properties) — a single tri-state value (`NoAccess` / `ViewOnly` / `Update`) from which all coarse-grained UI capability decisions are derived. The state defaults to `NoAccess` (deny by default).
- **Authorization result caching** (`UserAccess`) — a per-instance memo over `clsSecurityPrincipal.IsAuthorized` so repeated AD resource checks during a request do not re-query the security service.
- **Data-portal provisioning** (`ApplicationDataAccess`) — builds Oracle or SQL Server data portals from plain connection properties and exposes them as a keyed `IDataPortalInfo` registry, so a single manager can address multiple databases by name.
- **User-message accumulation and formatting** (`AppManagerBase.Message` / `AppendMessageLines`, `MessageFormatting`) — one message buffer per manager, de-duplicated, with a swappable line separator for web vs. console rendering.
- **Service-style response envelope** (`clsServiceAppManagerBase`, `ServiceResponse`, `ServiceMessage`, `ServiceMessageType`) — a second, lighter manager style for service/API callers, where the data portal is injected and results are returned as a categorized message set rather than mutated manager state.

## Component boundaries
- `AppManagerBase`: stateful, security-aware manager base — owns identity binding, its own data layer (lazily built from `SecurityPrincipal.UserName`), message buffer, and the `AppSecurityRole` classification. Only a `Protected` constructor exists, so no manager instance can be created without an identity.
- `UserAccess`: authorization-decision cache layer — binds to a `clsSecurityPrincipal` via `SetPrincipal` and memoizes `HasAccess` results in a case-insensitive `SortedList(Of String, Boolean)`. Contains no knowledge of any specific AD resource name; resource names are supplied entirely by callers.
- `ApplicationDataAccess`: data-portal provisioning boundary — builds `clsSQLDataPortal` / `clsMSOracleDataPortal` instances from connection properties and registers them in an `IDataPortalInfo` registry. The `DPI` setter is `Friend`, so only `AppManagerBase.InjectDPI` (same assembly) can register a portal handle from outside the class itself.
- `clsServiceAppManagerBase` / `ServiceResponse` / `ServiceMessage` / `ServiceMessageType`: a parallel, stateless manager style for service/API callers — the data portal is injected rather than owned, and it shares no base type with `AppManagerBase`; it carries none of the access-classification or messaging behavior of the stateful variant.
- `AppConstants` / `MessageFormatting`: shared constants (only `SAIFVALUE = "SAIF"`, no domain literal) and message-line formatting helpers used by both manager styles.

## Interaction model
- Domain application layers (`SAIF.Application.Claim`, then `SAIF.Application.Claim.Legal`) inherit `AppManagerBase`, `UserAccess`, and `AppConstants` to add domain-specific managers, resource names, and constants; `SAIF.Application` itself has no reference to any domain concept.
- A derived manager is constructed with a `clsSecurityPrincipal`, then follows the `Initialize` → context-validation (`OnValidContext`) → security-evaluation (`OnCheckSecurity`) → `Retrieve` / `Write` lifecycle defined by `AppManagerBase`; `OnCheckSecurity` and `OnValidContext` are declared `MustOverride` and are never invoked from within this library — invocation and the resulting `Mark*` classification call are the derived manager's responsibility.
- Authorization questions are delegated outward: `UserAccess.HasAccess` / `CheckAccess` forward caller-supplied resource names verbatim to `m_Principal.IsAuthorized` (from the `SAIF.BOF.Framework.Security` package) and cache the Boolean result; the library performs no AD, LDAP, or WCF call itself.
- Data access is delegated outward as well: `ApplicationDataAccess` only builds and registers Oracle/SQL Server data portals (`clsSQLDataPortal`, `clsMSOracleDataPortal`); it issues no SQL and applies no query, all of which is authored by consumers holding a portal handle.
- Service-style callers instead construct a `clsServiceAppManagerBase`-derived type with an injected DPI and receive a `ServiceResponse` containing categorized `ServiceMessage` entries, bypassing the `AppManagerBase` lifecycle entirely.

The following diagram shows high-level component interactions within and around this library.

```mermaid
flowchart TD
	UI[LegalMaintenance WebForms UI] --> Legal[SAIF.Application.Claim.Legal]
	Legal --> Claim[SAIF.Application.Claim]
	Claim --> AMB[AppManagerBase]
	Claim --> UA[UserAccess]
	AMB --> ADA[ApplicationDataAccess]
	AMB --> UA
	UA --> SP[clsSecurityPrincipal<br>SAIF.BOF.Framework.Security]
	ADA --> DP[clsSQLDataPortal / clsMSOracleDataPortal<br>SAIF.BOF.Framework.Connection]
	SVC[clsServiceAppManagerBase] --> ADA
```

## Sequence diagram
The following diagram shows the primary manager construction and authorization-check sequence.

```mermaid
sequenceDiagram
	participant Consumer as Derived manager
	participant AMB as AppManagerBase
	participant UA as UserAccess
	participant SP as clsSecurityPrincipal
	Consumer->>AMB: New(inSecurityPrincipal)
	Consumer->>UA: SetPrincipal(inSecurityPrincipal)
	Consumer->>AMB: Initialize
	Consumer->>UA: HasAccess(resourceName)
	UA->>UA: check cache (m_AccessControl)
	UA->>SP: IsAuthorized(resourceName)
	SP-->>UA: Boolean result
	UA-->>Consumer: cached Boolean
	Consumer->>AMB: MarkUpdate / MarkViewOnly / MarkNoAccess
```

## Design constraints
- No domain knowledge is embedded in this library; only `AppConstants.SAIFVALUE` carries an organizational literal, and no claim, legal, policy, or provider concept appears anywhere in the source.
- No SQL is authored and no direct database call is issued; the library only provisions connections via `ApplicationDataAccess`.
- No UI dependency exists at compile time, although `System.Web` is referenced and `<BR>` is the default message-line separator, so the message helpers are HTML-aware by convention.*
- The `ApplicationDataAccess.DPI` registry has a `Friend` setter — only `AppManagerBase.InjectDPI` (same assembly) can register a portal handle from outside the class; external callers must go through `CreateOraclePortal` / `CreateSQLServerPortal` or a derived manager.
- Two parallel manager styles (`AppManagerBase` and `clsServiceAppManagerBase`) share no base type and carry different capability sets, so consumers must choose one lineage per manager and cannot mix behavior across them.
- Authorization is delegated/pass-through: this library caches and exposes decisions produced by `clsSecurityPrincipal.IsAuthorized` and performs no AD, LDAP, or WCF call itself; whether that call is a WCF `SecurityService` hop, a direct AD lookup, or a framework-level cache is not determinable from this repository.**
- Access classification defaults to `NoAccess` (deny by default) until an explicit `Mark*` call grants `ViewOnly` or `Update`; `SecurityRole` and its derived `Is*` properties are read-only, so no external caller can elevate its own rights.
- `UserAccess` has no default `m_Principal`; calling `HasAccess` before `SetPrincipal` throws a `NullReferenceException` rather than failing via an explicit deny.
- The authorization cache is per-`UserAccess`-instance and keyed on the lower-cased resource name; a mid-session AD group change is not observed until a new instance is created.

> **Note:** Statements marked with * were inferred from code structure, naming conventions, or
> contextual evidence where direct confirmation was not available in source artifacts. Statements
> marked with ** could not be confirmed; treat as unknown until verified.

## Related documentation
- [Index](index.md)
- [Overview](overview.md)
- [Dependencies](dependencies.md)
- [Configuration](configuration.md)
- [Operations and processes](operations-processes.md)
- [Business rules](business-rules.md)
- [Security and authorization](security-authorization.md)
- [API reference](api/index.md)

## Sources
- `SAIF.Application/AppManagerBase.vb`
- `SAIF.Application/UserAccess.vb`
- `SAIF.Application/ApplicationDataAccess.vb`
- `SAIF.Application/clsServiceAppManagerBase.vb`
- `SAIF.Application/Service Based/*.vb`
- `SAIF.Application/AppConstants.vb`
- `SAIF.Application/Enums.vb`
- `SAIF.Application/MessageFormatting.vb`
- `SAIF.Application/SAIF.Application.vbproj`
- `SAIF.Application/Service Based/ServiceEnums.vb`
- `SAIF.Application/Service Based/ServiceResponse.vb`
- `SAIF.Application.Claim/ClaimAppManager.vb`
